﻿using System;
using System.Collections.Generic;
using Firefly.ExtensionMethods;
using Firefly.Framework.Input;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Firefly.Framework.Components.Cameras
{
    public class FreeCamera : CameraBase, ICamera, IInputProcessor
    {
        public FreeCamera(Game game)
            : base(game)
        {
            InitializeInputMaps();
        }

        #region IInputProcessor Members

        public int HoldThreshold { get; set; }
        public List<KeyMap> KeyMaps { get; protected set; }
        public List<MouseButtonMap> MouseButtonMaps { get; protected set; }
        public MouseAxisMap MouseAxisMap { get; protected set; }
        public MouseScrollWheelMap MouseScrollWheelMap { get; protected set; }
        public List<GamePadButtonMap> GamePadButtonMaps { get; protected set; }
        public List<GamePadDPadMap> GamePadDPadMaps { get; protected set; }
        public List<GamePadTriggerMap> GamePadTriggerMaps { get; protected set; }
        public List<GamePadThumbStickMap> GamePadThumbStickMaps { get; protected set; }

        public void InitializeInputMaps()
        {
            HoldThreshold = 100;
            KeyMaps = new List<KeyMap>();
            KeyMaps.Add(new KeyMap(new Keys[] { Keys.W }, CameraAction.MoveForward.ToString()));
            KeyMaps[0].MapPressed += new EventHandler<KeyMapEventArgs>(ProcessKeyMap);
            KeyMaps[0].MapHeld += new EventHandler<KeyMapEventArgs>(ProcessKeyMap);
            KeyMaps[0].HoldThreshold = HoldThreshold;
            KeyMaps.Add(new KeyMap(new Keys[] { Keys.S }, CameraAction.MoveBackward.ToString()));
            KeyMaps[1].MapPressed += new EventHandler<KeyMapEventArgs>(ProcessKeyMap);
            KeyMaps[1].MapHeld += new EventHandler<KeyMapEventArgs>(ProcessKeyMap);
            KeyMaps[1].HoldThreshold = HoldThreshold;
            KeyMaps.Add(new KeyMap(new Keys[] { Keys.A }, CameraAction.MoveLeft.ToString()));
            KeyMaps[2].MapPressed += new EventHandler<KeyMapEventArgs>(ProcessKeyMap);
            KeyMaps[2].MapHeld += new EventHandler<KeyMapEventArgs>(ProcessKeyMap);
            KeyMaps[2].HoldThreshold = HoldThreshold;
            KeyMaps.Add(new KeyMap(new Keys[] { Keys.D }, CameraAction.MoveRight.ToString()));
            KeyMaps[3].MapPressed += new EventHandler<KeyMapEventArgs>(ProcessKeyMap);
            KeyMaps[3].MapHeld += new EventHandler<KeyMapEventArgs>(ProcessKeyMap);
            KeyMaps[3].HoldThreshold = HoldThreshold;
            MouseAxisMap = new MouseAxisMap();
            MouseAxisMap.PositionChanged += new EventHandler<MouseAxisMapEventArgs>(ProcessMouseAxisMap);
        }

        protected void ProcessKeyMap(object sender, KeyMapEventArgs e)
        {
            if (Enabled)
            {
                KeyMap map = sender as KeyMap;

                if (map != null)
                {
                    switch (map.Action.ToEnum<CameraAction>())
                    {
                        case CameraAction.MoveForward:
                            MoveForward(TranslationStep);
                            break;
                        case CameraAction.MoveBackward:
                            MoveBackward(TranslationStep);
                            break;
                        case CameraAction.MoveLeft:
                            MoveLeft(TranslationStep);
                            break;
                        case CameraAction.MoveRight:
                            MoveRight(TranslationStep);
                            break;
                        case CameraAction.MoveUp:
                            MoveUp(TranslationStep);
                            break;
                        case CameraAction.MoveDown:
                            MoveDown(TranslationStep);
                            break;
                        case CameraAction.RotateUp:
                            RotateUp(RotationDelta);
                            break;
                        case CameraAction.RotateDown:
                            RotateDown(RotationDelta);
                            break;
                        case CameraAction.RotateLeft:
                            RotateLeft(RotationDelta);
                            break;
                        case CameraAction.RotateRight:
                            RotateRight(RotationDelta);
                            break;
                    }
                }
            }
        }

        protected void ProcessMouseAxisMap(object sender, MouseAxisMapEventArgs e)
        {
            if (Enabled)
            {
                MouseAxisMap map = sender as MouseAxisMap;

                if (map != null)
                {
                    Rotate(map.PositionDelta.ToVector3());
                }
            }
        }

        #endregion

        #region IDisposable Members

        ~FreeCamera()
        {
            Dispose(false);
        }

        #endregion
    }
}
